﻿using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

using WebImageResizer.Properties;
using WebImageResizer.Utils;

namespace WebImageResizer.ImageStores
{
	public class FileSystemImageStore : ImageStoreScavanger, IImageStore
	{
		#region Constants

		private const string CacheFileExtension = ".fsis";

		#endregion

		#region Readonly & Static Fields

		private readonly TimeSpan m_FileTimeout;
		private readonly string m_Root;

		#endregion

		#region Constructors

		public FileSystemImageStore(string root, TimeSpan fileTimeout, TimeSpan scavangeInterval)
			: base(scavangeInterval, true)
		{
			if (!Directory.Exists(root))
			{
				throw new ArgumentException("Directory " + root + " does not exist", root);
			}

			m_Root = root;
			m_FileTimeout = fileTimeout;
			AppScheduler.ScheduleTask(this);
		}

		public FileSystemImageStore() :
			this(GetFileSystemImageStorePath(),
				Settings.Default.ImageCacheTimeout,
				Settings.Default.ImageCleanRunInterval)
		{
		}

		#endregion

		#region Instance Methods

		protected override void CleanOldImages()
		{
			DateTime timeoutUtc = DateTime.UtcNow.Subtract(m_FileTimeout);
			string[] files = Directory.GetFiles(m_Root, "*" + CacheFileExtension);
			foreach (string fileName in files)
			{
				try
				{
					FileInfo fi = new FileInfo(fileName);
					if (fi.LastWriteTimeUtc < timeoutUtc)
					{
						fi.Attributes = FileAttributes.Normal;
						fi.Delete();
					}
				}
				catch (Exception e)
				{
					// Something unexpected happend
					Trace.Write(e);
				}
			}
		}

		private string GetFileName(string key)
		{
			string validFileName = FileSystemHelpers.ToValidFileName(key) + CacheFileExtension;
			string completefileName = Path.Combine(m_Root, validFileName);
			return completefileName;
		}

		#endregion

		#region IImageStore Members

		public byte[] GetImageData(string key)
		{
			// Don't check file age here, to slow, let the scavanger handle that
			string fileName = GetFileName(key);
			return !FileSystemHelpers.FileExists(fileName) ? null : File.ReadAllBytes(fileName);
		}

		public void PutImageData(string key, byte[] imageData)
		{
			// Do writing in thread pool, so request can return as quickly as possible
			ThreadPool.QueueUserWorkItem(
				o =>
					{
						try
						{
							string fileName = GetFileName(key);
							File.WriteAllBytes(fileName, imageData);
						}
						catch (Exception e)
						{
							// Something unexpected happend
							Trace.Write(e);
						}
					});
		}

		#endregion

		#region Class Methods

		private static string GetFileSystemImageStorePath()
		{
			object tmp = AppDomain.CurrentDomain.GetData("DataDirectory");
			string appDataDirectory = tmp != null ? tmp.ToString() : string.Empty;
			return Settings.Default.FileSystemImageStorePath.Replace("|AppData|", appDataDirectory);
		}

		#endregion
	}
}